#include "CC_header.h"
#include <windows.h>

using namespace std;

LARGE_INTEGER frequency;

float GetTimeDifference(LARGE_INTEGER *pStart, LARGE_INTEGER *pEnd)
{
    float result;
    result = (float)(pEnd->QuadPart - pStart->QuadPart);
    result /= frequency.QuadPart;
    return result;
}

static void CC_choseprofiles(void)
{
	if (cgGLIsProfileSupported(CG_PROFILE_FP30))  // Advanced Fragment Profile 
		 fragmentprofile = CG_PROFILE_FP30;
	 else if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1))  // Standard Frag Profile
		 fragmentprofile = CG_PROFILE_ARBFP1;
	 else
	 {
		 fprintf(stderr, "Video card does not support fragment programs, exiting...\n");
		 exit(-1);
	 }
	 if (cgGLIsProfileSupported(CG_PROFILE_VP30))  // Advanced Vertex Profile 
		 vertexprofile = CG_PROFILE_VP30;
	 else if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1))  // Standard Vertex Profile
		 vertexprofile = CG_PROFILE_ARBVP1;
	 else
	 {
		 fprintf(stderr, "Video card does not support vertex programs, exiting...\n");
		 exit(-1);
	 }
}

static void CC_loadparams(void)
{
 // Assign to uniform inputs in the cg file

 // Fragment Parameters

 // Non-uniform inputs in file
 testTextureParam = cgGetNamedParameter(fragmentProgram, "testTexture");
 CheckCgError();
 decalCoordsParam = cgGetNamedParameter(fragmentProgram, "IN.decalCoords");
 CheckCgError();
}

static void Display_image(void)
{
	LARGE_INTEGER start_su, end_su;
    QueryPerformanceCounter(&start_su);
		
	glClear(GL_COLOR_BUFFER_BIT); //| GL_DEPTH_BUFFER_BIT);

	glViewport(0, 0, xsize, ysize);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-1, 1, 1, -1, -10.0f, 10.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glEnable(GL_TEXTURE_RECTANGLE_ARB);

	cgGLBindProgram(fragmentProgram);
	CheckCgError();

	cgGLBindProgram(vertexProgram);
	CheckCgError();

	if (load)
	{
		if (image)
		{
            if (load_texture("same_as_fpga.yuv"))
			//if (load_texture("gpu_test1280x720.yuv"))
				printf("Texture Read Sucessful...\n");
		}
		else
		{
            if (load_texture("lenna800.bmp"))
			//if (load_texture("face.ppm"))
				printf("Texture Read Sucessful...\n");
		}
		
		load = false;
	}

	float time = 0;

	cgGLSetTextureParameter(testTextureParam, g_Texture.id);

	cgGLEnableTextureParameter(testTextureParam);

	cgGLEnableProfile(fragmentprofile);
	cgGLEnableProfile(vertexprofile);

	glFinish();

	QueryPerformanceCounter(&end_su);
	printf("Setup Time is: %.6f secs\n", GetTimeDifference(&start_su, &end_su));  

	for (int i=0; i<renders; i++)
	{

	LARGE_INTEGER start, end;
    QueryPerformanceCounter(&start);
	
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
		glTexCoord2f(float(xsize), 0.0f); glVertex2f(1.0f, -1.0f);
		glTexCoord2f(float(xsize), float(ysize)); glVertex2f(1.0f, 1.0f);
		glTexCoord2f(0.0f, float(ysize)); glVertex2f(-1.0f, 1.0f);
	glEnd();
	glFinish();

	QueryPerformanceCounter(&end);
    time += GetTimeDifference(&start, &end);

	glutSwapBuffers();
	glFinish();
	
	}

	cgGLDisableProfile(fragmentprofile);
	cgGLDisableProfile(vertexprofile);

	cgGLDisableTextureParameter(testTextureParam);


	time /= renders;

	printf("%.3f secs, %.2f Mpixels/sec\n", time, xsize*ysize / (time*1000000.0));
	
}

static void InitializeGlut(int *argc, char *argv[])
{
	glutInit(argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(xsize,ysize);
	glutInitWindowPosition(0,0);
	glutCreateWindow("FIR Filtering");
	glutDisplayFunc(Display_image);
}

 void p_keyboard(unsigned char key, int x, int y)
 {
	 switch(key)
	 {
	 // Vertex Program Variables
	 case '2' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_2x2.cg", fragmentprofile, "main", NULL); break;
	 case '3' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_3x3.cg", fragmentprofile, "main", NULL); break;
	 case '4' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_4x4.cg", fragmentprofile, "main", NULL); break;
	 case '5' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_5x5.cg", fragmentprofile, "main", NULL); break;
	 case '6' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_6x6.cg", fragmentprofile, "main", NULL); break;
	 case '7' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_7x7.cg", fragmentprofile, "main", NULL); break;
	 case '8' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_8x8.cg", fragmentprofile, "main", NULL); break;
	 case '9' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_9x9.cg", fragmentprofile, "main", NULL); break;
	 case '0' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_10x10.cg", fragmentprofile, "main", NULL); break;
	 case 'q' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_11x11.cg", fragmentprofile, "main", NULL); break;
	 case 'w' : fragmentProgram = cgCreateProgramFromFile(Context, CG_SOURCE, CWD "fir_12x12.cg", fragmentprofile, "main", NULL); break;
	 }

	 if (key == '2' | key == '3' | key == '4' | key == '5' | key == '6' | key == '7' | 
		 key == '8' | key == '9' | key == '0' | key == 'q' | key == 'w')
	 {
		 CheckCgError();
	 	 fprintf(stderr, "LAST LISTING----%s----\n", cgGetLastListing(Context));
		 fprintf(stderr, "---- PROGRAM BEGIN ----\n%s---- PROGRAM END ----\n",
         cgGetProgramString(fragmentProgram, CG_COMPILED_PROGRAM));
     	 if (fragmentProgram != NULL)
	     {
		  cgGLLoadProgram(fragmentProgram);
		  CheckCgError();
	     }
	 }

	 glutPostRedisplay();
 }

 int main(int argc, char *argv[])
 {

	 InitializeGlut(&argc, argv);

	 CC_choseprofiles();

	 // Test Cg Context creation
	 Context = cgCreateContext();
	 CheckCgError();

	 // Test adding source text to context
     fragmentProgram = cgCreateProgramFromFile(Context,
                                    CG_SOURCE, CWD "fir_7x7.cg",//"fir_2x2.cg",
                                    fragmentprofile,
                                    "main", NULL);
	 CheckCgError();
	 
	 fprintf(stderr, "LAST LISTING----%s----\n", cgGetLastListing(Context));

	 fprintf(stderr, "---- PROGRAM BEGIN ----\n%s---- PROGRAM END ----\n",
        cgGetProgramString(fragmentProgram, CG_COMPILED_PROGRAM));

	 if (fragmentProgram != NULL)
	 {
		 cgGLLoadProgram(fragmentProgram);
		 CheckCgError();
	 }

	 vertexProgram = cgCreateProgramFromFile(Context,
                                    CG_SOURCE, CWD "ccr_vertex.cg",
                                    vertexprofile,
                                    "ccr_vertex", NULL);
	 CheckCgError();

 	 fprintf(stderr, "LAST LISTING----%s----\n", cgGetLastListing(Context));

	 fprintf(stderr, "---- PROGRAM BEGIN ----\n%s---- PROGRAM END ----\n",
        cgGetProgramString(vertexProgram, CG_COMPILED_PROGRAM));

	 if (vertexProgram != NULL)
	 {
		 cgGLLoadProgram(vertexProgram);
		 CheckCgError();
	 }

	 if (fragmentProgram != NULL && vertexProgram != NULL)
		CC_loadparams();

	 QueryPerformanceFrequency(&frequency);


	 glutKeyboardFunc(p_keyboard);

     glutMainLoop();

	 cgDestroyProgram(fragmentProgram);
	 cgDestroyProgram(vertexProgram);

	 cgDestroyContext(Context);

	 glDeleteTextures(1, &g_Texture.id);

	 return 0;
 }